package com.zsk.shop.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsk.shop.common.base.BaseResponse;
import com.zsk.shop.common.base.page.BasePageFactory;
import com.zsk.shop.common.constant.Constant;
import com.zsk.shop.common.utils.DateUtils;
import com.zsk.shop.common.utils.EntityConvertUtils;
import com.zsk.shop.common.utils.ToolUtil;
import com.zsk.shop.entity.DataDictionary;
import com.zsk.shop.entity.VerificationCode;
import com.zsk.shop.enums.EnumVerificationType;
import com.zsk.shop.mapper.VerificationCodeMapper;
import com.zsk.shop.model.results.VerificationCodeResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

@Slf4j
@Service
public class VerificationCodeService extends ServiceImpl<VerificationCodeMapper, VerificationCode> {

    @Resource
    private DataDictionaryService dataDictionaryService;

    //短信失效时间为5分钟
    private final static Integer INVALID_TIME = 5;

    public Boolean insertCode(String code, String phone, Integer type) {
        VerificationCode verificationCode = VerificationCode.builder()
                .phone(phone).type(type).code(code)
                .createTime(new Date()).invalidTime(DateUtils.addMinute(INVALID_TIME)).build();
        return this.save(verificationCode);
    }

    /**
     * @param phone
     * @param type
     * @param code
     * @return true-校验通过 false-校验不通过
     */
    public Boolean checkCode(String phone, Integer type, String code) {
        //增加验证码判定数据
        DataDictionary dictionary = dataDictionaryService.getValueByKey(Constant.CAN_USE_SHORT_VERIFICATION_CODE);
        String value = ToolUtil.isEmpty(dictionary) ? "true" : dictionary.getValue();
        if (value.equals("true")) {
            Date date = new Date();
            if (code.equals(DateUtils.format(date, DateUtils.MMdd) + "0" + DateUtils.getDayOfWeek(date))) {
                //如果是找回密码，对应生成可找回数据
                insertCanSetNewPwdInfo(phone, type);
                return true;
            }
        }
        LambdaQueryWrapper<VerificationCode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VerificationCode::getCode, code);
        queryWrapper.eq(VerificationCode::getPhone, phone);
        queryWrapper.eq(VerificationCode::getType, type);
        queryWrapper.eq(VerificationCode::getUsed, false);
        queryWrapper.gt(VerificationCode::getInvalidTime, new Date());
        queryWrapper.last("limit 1");
        VerificationCode verificationCode = this.getOne(queryWrapper);
        if (ToolUtil.isNotEmpty(verificationCode)) {
            //使失效
            verificationCode.setUsed(true);
            verificationCode.setUseTime(new Date());
            this.updateById(verificationCode);
            //如果是找回密码，对应生成可找回数据
            insertCanSetNewPwdInfo(phone, type);
            return true;
        } else {
            return false;
        }
    }

    private void insertCanSetNewPwdInfo(String phone, Integer type) {
        if (type.equals(EnumVerificationType.CHANGE_PWD.getCode())) {
//            canSetNewPwdService.add(phone);
        }
        return;
    }

    public static String genCode() {
        //生成验证码
        Random r = new Random();
        String code = "";
        for (int i = 0; i < 6; i++) {
            String n = r.nextInt(10) + "";
            code += n;
        }
        return code;
    }

    /**
     * 当前手机号是否超过发送频率限制
     * 1分钟内短信发送条数不超过：   *  1
     * 1小时内短信发送条数不超过：   *  5
     * 1个自然日内短信发送条数不超过：     * 10
     *
     * @param phone
     * @return true-超过频率，false-未超过频率
     */
    public Boolean overLimit(String phone) {
        LambdaQueryWrapper<VerificationCode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(VerificationCode::getId, VerificationCode::getPhone, VerificationCode::getCreateTime);
        queryWrapper.eq(VerificationCode::getPhone, phone);
        queryWrapper.ge(VerificationCode::getCreateTime, DateUtils.addDay(-1));
        //过去24小时发送次数
        List<VerificationCode> list = this.list(queryWrapper);
        //限制日频率
        List<VerificationCode> dayList = list.stream().filter(x -> x.getCreateTime().compareTo(
                DateUtils.getDateStart(new Date())) >= 0).collect(Collectors.toList());
        if (dayList.size() >= 10) {
            return true;
        }
        //限制小时频率
        List<VerificationCode> hourList = list.stream().filter(x -> x.getCreateTime().compareTo(
                DateUtils.addHour(-1)) >= 0).collect(Collectors.toList());
        if (hourList.size() >= 5) {
            return true;
        }
        //限制分钟频率
        List<VerificationCode> minuteList = hourList.stream().filter(x -> x.getCreateTime().compareTo(
                DateUtils.addMinute(-1)) >= 0).collect(Collectors.toList());
        if (minuteList.size() >= 1) {
            return true;
        }
        return false;
    }

    public BaseResponse<VerificationCodeResult> getCodeList(String phone, Integer type) {
        DataDictionary dictionary = dataDictionaryService.getValueByKey(Constant.CAN_SHOW_VERIFICATION_CODE);
        String value = ToolUtil.isEmpty(dictionary) ? "false" : dictionary.getValue();
        if (!value.equals("true")) {
            return BaseResponse.error("当前不支持查看");
        }
        Page pageContext = BasePageFactory.defaultPage();
        LambdaQueryWrapper<VerificationCode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VerificationCode::getUsed, false);
        queryWrapper.ge(VerificationCode::getInvalidTime, new Date());
        queryWrapper.orderByDesc(VerificationCode::getCreateTime);
        if (ToolUtil.isNotEmpty(phone)) {
            queryWrapper.like(VerificationCode::getPhone, phone);
        }
        if (ToolUtil.isNotEmpty(type)) {
            queryWrapper.eq(VerificationCode::getType, type);
        }
        IPage page = this.page(pageContext, queryWrapper);
        List<VerificationCodeResult> list = EntityConvertUtils.convertAListToBList(page.getRecords(), VerificationCodeResult.class);
        for (VerificationCodeResult result : list) {
            result.setTypeStr(EnumVerificationType.getNameByCode(result.getType()));
        }
        return BaseResponse.success(list);
    }

}
